<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.1.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"chenmenghui.gitee.io","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":true,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":false,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="对象基础本章主要内容有  类和对象:声明类及实例化对象 构造方法:自动加载对象 基本数据类型和类的类型: 继承:为什么需要继承和如何是用继承 可见性:整合对象接口并保护类中的方法和属性不受干涉  类和对象编写第一个类123class ShopProduce &amp;#123;    &#x2F;&#x2F; todo&amp;#125; 简单的说,类是用于生成对象的代码模板.使用class关键字和一个任意的类名来声明类.类名可以是">
<meta property="og:type" content="article">
<meta property="og:title" content="PHP之《深入PHP面向对象、模式与实践》">
<meta property="og:url" content="https://chenmenghui.gitee.io/posts/50791.html">
<meta property="og:site_name" content="陈孟辉的学习笔记">
<meta property="og:description" content="对象基础本章主要内容有  类和对象:声明类及实例化对象 构造方法:自动加载对象 基本数据类型和类的类型: 继承:为什么需要继承和如何是用继承 可见性:整合对象接口并保护类中的方法和属性不受干涉  类和对象编写第一个类123class ShopProduce &amp;#123;    &#x2F;&#x2F; todo&amp;#125; 简单的说,类是用于生成对象的代码模板.使用class关键字和一个任意的类名来声明类.类名可以是">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2018-10-02T16:00:00.000Z">
<meta property="article:modified_time" content="2022-04-15T05:54:44.844Z">
<meta property="article:author" content="陈孟辉">
<meta property="article:tag" content="PHP">
<meta property="article:tag" content="图书">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://chenmenghui.gitee.io/posts/50791.html">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>PHP之《深入PHP面向对象、模式与实践》 | 陈孟辉的学习笔记</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/rss2.xml" title="陈孟辉的学习笔记" type="application/rss+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">陈孟辉的学习笔记</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">加油吧骚年</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-rss">

    <a href="/rss2.xml" rel="section"><i class="fa fa-rss fa-fw"></i>RSS</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://chenmenghui.gitee.io/posts/50791.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="陈孟辉">
      <meta itemprop="description" content="日积月藏，不做咸鱼。这里是陈孟辉的个人学习笔记，现就职于北京瑞友科技，负责维护企业ERP系统。">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="陈孟辉的学习笔记">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          PHP之《深入PHP面向对象、模式与实践》
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2018-10-03 00:00:00" itemprop="dateCreated datePublished" datetime="2018-10-03T00:00:00+08:00">2018-10-03</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-04-15 13:54:44" itemprop="dateModified" datetime="2022-04-15T13:54:44+08:00">2022-04-15</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E5%9B%BE%E4%B9%A6/" itemprop="url" rel="index"><span itemprop="name">图书</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E5%9B%BE%E4%B9%A6/PHP/" itemprop="url" rel="index"><span itemprop="name">PHP</span></a>
                </span>
            </span>

          
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/posts/50791.html#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/posts/50791.html" itemprop="commentCount"></span>
    </a>
  </span>
  
  <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>17k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>16 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="对象基础"><a href="#对象基础" class="headerlink" title="对象基础"></a>对象基础</h1><p>本章主要内容有</p>
<ul>
<li>类和对象:声明类及实例化对象</li>
<li>构造方法:自动加载对象</li>
<li>基本数据类型和类的类型:</li>
<li>继承:为什么需要继承和如何是用继承</li>
<li>可见性:整合对象接口并保护类中的方法和属性不受干涉</li>
</ul>
<h2 id="类和对象"><a href="#类和对象" class="headerlink" title="类和对象"></a>类和对象</h2><h3 id="编写第一个类"><a href="#编写第一个类" class="headerlink" title="编写第一个类"></a>编写第一个类</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ShopProduce</span> </span>&#123;</span><br><span class="line">    <span class="comment">// todo</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>简单的说,类是用于生成对象的代码模板.使用class关键字和一个任意的类名来声明类.类名可以是任意数字和字母的组合,但不能以数字开头.和一个类关联的代码必须用大括号括起来.</p>
<h3 id="第一个对象-或两个"><a href="#第一个对象-或两个" class="headerlink" title="第一个对象(或两个)"></a>第一个对象(或两个)</h3><p>如果类是声明对象的模板,那么对象是根据类中定义的模板所构造的数据.对象可以被说成类的”实例”,它是由类定义的数据类型.</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="variable">$product1</span> = <span class="keyword">new</span> <span class="title class_">ShopProducee</span>();</span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="variable">$product1</span>); <span class="comment">// 可以看到包含对象ID的字符串</span></span><br></pre></td></tr></table></figure>

<h2 id="设置类中的属性"><a href="#设置类中的属性" class="headerlink" title="设置类中的属性"></a>设置类中的属性</h2><blockquote>
<p>类的属性和标准的变量很相似,不过必须在声明和赋值前加一个代表可见性的关键字.这个关键字可以是public,protected或private,它决定了属性的作用域.</p>
</blockquote>
<p>类可以定义被称为属性的特定变量.属性也称为成员变量,用来存放对象之间互不相同的数据.</p>
<p>虽然php并没有强制所有的属性都要在类中声明,但是那种动态地增加属性到对象的方式并不值得推荐.比如:</p>
<ul>
<li>特定意义不明显,难以及时发现属性中语法之外的错误</li>
<li>类太过松散,因为属性都是在客户端代码中实现的</li>
<li>不得不重复做出一些经常做的事情</li>
</ul>
<h2 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h2><blockquote>
<p>function关键字在方法名之前.方法名之后的圆括号是可选的参数列表.方法体用大括号括起来</p>
</blockquote>
<p>属性可以让对象存储数据,类方法则可以让对象执行任务.方法是类中声明的特殊函数.</p>
<h2 id="参数和类型"><a href="#参数和类型" class="headerlink" title="参数和类型"></a>参数和类型</h2><p>数据类型决定了PHP代码中处理数据的方式—-从更高层次的意义上来说,每个类都定义一种数据类型.</p>
<p>在PHP中,定义方法和函数时不需要指定参数的数据类型,在便利的同时,也带来了一些隐患.在需要特殊指定类型的场合,这种便利会带来一些隐患</p>
<h3 id="基本类型"><a href="#基本类型" class="headerlink" title="基本类型"></a>基本类型</h3><p>数据的类型决定了PHP代码中处理数据的方式.比如,使用字符串类型显示字符数据并用字符串函数处理这些数据等等.这些类型被称为<strong>基本类型</strong>.</p>
<p>从更高层次上来说,每一个类都定义了一种数据类型.因此ShopProduct对象属于基本类型,但同时也属于ShopProduct类这一类型.</p>
<h4 id="基本数据类型"><a href="#基本数据类型" class="headerlink" title="基本数据类型"></a>基本数据类型</h4><p>需要时刻留意代码中的数据类型,比如”false”和false两者结果相反的解析可能会导致截然不同的结果.解决这种问题的方法总结如下</p>
<ul>
<li>检测类型</li>
<li>转换类型</li>
<li>依赖良好清晰的文档(无论哪种模式,都需要这个)</li>
</ul>
<p>无论如何解决这类问题,都要认真考虑一件事情:类型处理.PHP是一种弱类型的语言.我们不能依赖编译器来防止类型相关的bug,必须考虑当非法数据类型的参数传递给方法是,会产生什么样的后果.我们不能完全信任客户端程序员,应始终在方法中处理他们引入的无用信息.</p>
<h4 id="获得提示-对象类型"><a href="#获得提示-对象类型" class="headerlink" title="获得提示:对象类型"></a>获得提示:对象类型</h4><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">write</span>(<span class="params">ShopProduct <span class="variable">$shopProduct</span></span>) </span>&#123; </span><br><span class="line">    <span class="comment">// todo</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>最新的php7也可以把string之类东西作为类型提示.刚刚说的处理这类问题需要<em>检测类型</em>,<em>转化类型</em>或<em>良好的文档</em>,现在就会通过直接指定解决了.</p>
<p>需要注意的是,虽然自动类型检查是防止bug的极佳途径,但是自动类型检查实在代码运行的时候才能生效.</p>
<p>数据类型和类确有很多相似之处,他们有一个关键的不同之处:定义一个类也就定义了一个类型,但是一个类型可以用于描述一个家族的众多类.<br>这种将不同的类放在一个类型之下的机制被称为继承.</p>
<h2 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h2><p>继承是从一个基类得到一个或多个派生类的机制</p>
<p>继承自另外一个类的类被称为该类的子类.子类将继承父类的特性.这些特性由属性和方法组成.子类可以增加父类之外的新功能.</p>
<h3 id="继承问题"><a href="#继承问题" class="headerlink" title="继承问题"></a>继承问题</h3><h3 id="使用继承"><a href="#使用继承" class="headerlink" title="使用继承"></a>使用继承</h3><p>创建继承的第一步是找到现有的基类元素中不适合放在一起,或者不需要进行特殊处理的类方法.</p>
<h4 id="构造方法和继承"><a href="#构造方法和继承" class="headerlink" title="构造方法和继承"></a>构造方法和继承</h4><p>在子类中定义构造方法是,需要传递参数给父类的构造方法,否则得到的可能是一个构造不完整的对象.<br>要调用父类的方法,首先要找到一个引用类本身的途径:句柄(handle).PHP在这里提供了parent关键字.<br>要引用一个类而不是对象的方法,可以使用::而不是-&gt;</p>
<h4 id="调用被覆写的方法"><a href="#调用被覆写的方法" class="headerlink" title="调用被覆写的方法"></a>调用被覆写的方法</h4><p>parent关键字可以在任何覆写父类方法中使用.覆写一个父类的方法是,并不希望删除父类的功能,而是扩展它,通过在当前对象中调用父类的方法可以达到这个目的.</p>
<h3 id="public-private-protected-管理类的访问"><a href="#public-private-protected-管理类的访问" class="headerlink" title="public private protected:管理类的访问"></a>public private protected:管理类的访问</h3><p>类中的元素可以被声明为public private protected</p>
<ul>
<li>public:在任何地方都可以访问</li>
<li>private:只能在当前类中才能访问,即使是子类也不可以</li>
<li>protected: 可在当前类及其子类中访问,外部代码无权访问</li>
</ul>
<h1 id="高级特性"><a href="#高级特性" class="headerlink" title="高级特性"></a>高级特性</h1><p>本章的主要内容有:</p>
<ul>
<li>静态方法和属性:通过类而不是对象来获取数据和功能</li>
<li>抽象类和接口:设计和实现相分离</li>
<li>错误处理:异常</li>
<li>Final类和方法:限制继承</li>
<li>拦截器方法:自动委托</li>
<li>析构方法:对象销毁前的清理工作</li>
<li>克隆对象:创建对象的副本</li>
<li>把对象解析成字符串:创建摘要型方法</li>
<li>回调:用匿名函数为组件添加功能</li>
</ul>
<h2 id="静态方法和属性"><a href="#静态方法和属性" class="headerlink" title="静态方法和属性"></a>静态方法和属性</h2><p>我们不仅可以通过对象访问方法和属性,还可以通过类来访问它们.这样的方法和属性是”静态的”,必须使用static关键字来声明</p>
<p>静态方法是以类为作用域的函数.静态方法不能访问这个类中的普通属性,因为那些属性属于一个对象,但可以访问静态属性.如果修改一个静态属性,那么这个类的所有实例都能访问到这个新值.<br>因为通过类而不是实例来访问静态元素,所以访问静态元素时不需要引用对象的变量,而是使用::来连接类名和属性或者类名和方法.</p>
<blockquote>
<p>只用使用parent关键字调用方法时,才能对一个非静态方法进行静态形式的调用.其他任何情况都需要先生成一个对象,然后使用-&gt;符号调用对象中的方法.<br>也就是说,除非访问一个被覆写的方法,否则永远只能用::访问被明确声明为static的方法或属性.</p>
</blockquote>
<h2 id="常量属性"><a href="#常量属性" class="headerlink" title="常量属性"></a>常量属性</h2><p>虽然常量属性是公共的,可静态访问的,但客户端代码不能改变它们.</p>
<p>常量属性只包含基本数据类型的值.不能将一个对象指派给常量.像静态属性一样，只能通过类而不能通过类的实例访问常量属性.</p>
<h2 id="抽象类"><a href="#抽象类" class="headerlink" title="抽象类"></a>抽象类</h2><p>抽象类不能直接实例化.抽象类中只定义或部分实现子类需要的方法.子类可以继承它并且通过实现其中的抽象方法,使抽象类具体化.</p>
<p>抽象类的每个子类都必须实现抽象类中的所有抽象方法,或者把他们自身也声明为抽象方法.扩展类不仅仅负责简单实现抽象类中的方法,还必须重新声明方法.新的实现方法的访问控制不能比抽象方法的访问控制更加严格.新实现方法的参数个数应该和抽象方法的参数个数一样,重新生成对应的类型提示.</p>
<h2 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h2><p>抽象类提供了具体实现的标准,而接口(interface)则是纯粹的模板.接口只能定义功能而不包含实现内容.接口可用关键字interface声明.接口可以包含属性和方法声明,但是方法体为空. </p>
<h2 id="trait"><a href="#trait" class="headerlink" title="trait"></a>trait</h2><p>和java一样，php不支持多重继承。但接口可以帮助我们解决这个问题。换言之，php中的类只能有一个父类，却可以实现多个接口，这个类对于实现的每个接口都有相应的类型。</p>
<p>接口可以提供没有任何实现的类型。但如果我们希望在继承层次中共享实现，可以是使用trait。</p>
<p>trait是类似类的结构，它本身不能被实例化，但可以混合到类中。trait中定义的任何方法都可以被使用它的任何类所使用的。trait可以改变类的结构，但无法更改其类型。我们可以把trait视为包含到类中的部分。</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">trait</span> <span class="title">PriceUtilities</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line"><span class="comment">//    private $tax_rate = 17;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">* <span class="doctag">@param</span> float $price</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> float</span></span><br><span class="line"><span class="comment">*/</span><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">calculateTax</span>(<span class="params"><span class="keyword">float</span> <span class="variable">$price</span></span>): <span class="title">float</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">getTaxRate</span>() * <span class="variable">$price</span> / <span class="number">100</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">abstract</span> <span class="function"><span class="keyword">function</span> <span class="title">getTaxRate</span>(<span class="params"></span>): <span class="title">float</span></span>; <span class="comment">// trait中定义抽象方法</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">trait</span> <span class="title">StaticPriceUtilities</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="built_in">static</span> <span class="variable">$tax_rate</span> = <span class="number">17</span>; <span class="comment">// 改变trait中方法的访问权限</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">calculateTax</span>(<span class="params"><span class="keyword">float</span> <span class="variable">$price</span></span>): <span class="title">float</span> // <span class="title">trait</span> 可以使用静态方法</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">self</span>::<span class="variable">$tax_rate</span> * <span class="variable">$price</span> / <span class="number">100</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">trait</span> <span class="title">TaxTools</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">calculateTax</span>(<span class="params"><span class="keyword">float</span> <span class="variable">$price</span></span>): <span class="title">float</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">222</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ShopProduct</span> <span class="keyword">implements</span> <span class="title">IdentityObject</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">use</span> <span class="title">PriceUtilities</span>, <span class="title">IdentityTrait</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getTaxRate</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">17</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StaticShopProduct</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">use</span> <span class="title">StaticPriceUtilities</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Service</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UtilityService</span> <span class="keyword">extends</span> <span class="title">Service</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">use</span> <span class="title">PriceUtilities</span>, <span class="title">TaxTools</span> &#123;</span><br><span class="line">        <span class="title">TaxTools</span>::<span class="title">calculateTax</span> <span class="title">insteadof</span> <span class="title">PriceUtilities</span>; <span class="comment">// 使用instanceof管理方法名冲突</span></span><br><span class="line">        <span class="title class_">PriceUtilities</span>::<span class="variable constant_">calculateTax</span> <span class="keyword">as</span> basicTax;           <span class="comment">// 使用别名重写trait的方法 </span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getTaxRate</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">123</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">trait</span> <span class="title">IdentityTrait</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">generateId</span>(<span class="params"></span>): <span class="title">string</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_ invoke__">uniqid</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">IdentityObject</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">generateId</span>(<span class="params"></span>): <span class="title">string</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">$p</span> = <span class="keyword">new</span> <span class="title class_">ShopProduct</span>();</span><br><span class="line"><span class="keyword">print</span> <span class="variable">$p</span>-&gt;<span class="title function_ invoke__">calculateTax</span>(<span class="number">100</span>) . <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"><span class="keyword">print</span> <span class="variable">$p</span>-&gt;<span class="title function_ invoke__">generateId</span>() . <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="variable">$u</span> = <span class="keyword">new</span> <span class="title class_">UtilityService</span>();</span><br><span class="line"><span class="keyword">print</span> <span class="variable">$u</span>-&gt;<span class="title function_ invoke__">calculateTax</span>(<span class="number">100</span>) . <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"><span class="keyword">print</span> <span class="variable">$u</span>-&gt;<span class="title function_ invoke__">basicTax</span>(<span class="number">100</span>) . <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="variable">$sp</span> = <span class="keyword">new</span> <span class="title class_">StaticShopProduct</span>();</span><br><span class="line"><span class="keyword">print</span> <span class="variable">$sp</span>::<span class="title function_ invoke__">calculateTax</span>(<span class="number">100</span>) . <span class="string">&quot;\n&quot;</span>;</span><br></pre></td></tr></table></figure>

<h2 id="延迟静态绑定-static关键字"><a href="#延迟静态绑定-static关键字" class="headerlink" title="延迟静态绑定:static关键字"></a>延迟静态绑定:static关键字</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">DomainObject</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">create</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">static</span>(); <span class="comment">// #1 return new self();</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> <span class="keyword">extends</span> <span class="title">DomainObject</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>self指的不是调用上下文,而是解析上下文.所以,上代码中的#1的static如果换成self就会出错.因为这里的self被解析成create()的DomainObject,而不是解析为调用self的User</p>
<p>static类似于self,但它指的是被调用的类而不是包含类.在本例中,它的意思是调用User::create()将生成一个新的User对象,而不是试图实例化一个DomainObject对象.</p>
<p>static关键字不仅仅可以用于实例化.和self及parent一样,static还可以用作静态方法调用的标识符,甚至是从非静态上下文中调用.</p>
<p>假设想为DomainObject引入组的概念.默认所有类属于default级别,同时也可以为继承层次结构的某些分支重写类别.</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">DomainObject</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$group</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;group = <span class="built_in">static</span>::<span class="title function_ invoke__">getGroup</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">create</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">static</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">getGroup</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;Default&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> <span class="keyword">extends</span> <span class="title">DomainObject</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Document</span> <span class="keyword">extends</span> <span class="title">DomainObject</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">getGroup</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Document&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SpreadSheet</span> <span class="keyword">extends</span> <span class="title">Document</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title function_ invoke__">print_r</span>(<span class="title class_">User</span>::<span class="title function_ invoke__">create</span>());</span><br><span class="line"><span class="title function_ invoke__">print_r</span>(<span class="title class_">SpreadSheet</span>::<span class="title function_ invoke__">create</span>());</span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="http://php.net/manual/zh/language.oop5.late-static-bindings.php">注意static的问题</a>:</p>
<p>在非静态环境下，所调用的类即为该对象实例所属的类.由于 $this-&gt; 会在同一作用范围内尝试调用私有方法，而 static:: 则可能给出不同结果.另一个区别是 static:: 只能用于静态属性.</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="string">&quot;success!\n&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">foo</span>();</span><br><span class="line">        <span class="built_in">static</span>::<span class="title function_ invoke__">foo</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span> <span class="keyword">extends</span> <span class="title">A</span> </span>&#123;</span><br><span class="line">   <span class="comment">/* foo() will be copied to B, hence its scope will still be A and</span></span><br><span class="line"><span class="comment">    * the call be successful */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">C</span> <span class="keyword">extends</span> <span class="title">A</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="comment">/* original method is replaced; the scope of the new one is C */</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">$b</span> = <span class="keyword">new</span> <span class="title function_ invoke__">B</span>();</span><br><span class="line"><span class="variable">$b</span>-&gt;<span class="title function_ invoke__">test</span>();</span><br><span class="line"><span class="variable">$c</span> = <span class="keyword">new</span> <span class="title function_ invoke__">C</span>();</span><br><span class="line"><span class="variable">$c</span>-&gt;<span class="title function_ invoke__">test</span>();   <span class="comment">// fail 此处A中static::foo()会调用C中的私有方法foo(),故会报错</span></span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure>

<p>后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止.另一方面，如果静态调用使用 parent:: 或者 self:: 将转发调用信息.</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="built_in">static</span>::<span class="title function_ invoke__">who</span>(); <span class="comment">// 留意此处,static究竟指向谁</span></span><br><span class="line">                       <span class="comment">// 如果是self::who(),就都是A了.这就是特别需要注意的地方</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">who</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="keyword">__CLASS__</span>.<span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span> <span class="keyword">extends</span> <span class="title">A</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        A::<span class="title function_ invoke__">foo</span>(); <span class="comment">// 非转发调用</span></span><br><span class="line">        <span class="built_in">static</span>::<span class="title function_ invoke__">foo</span>();</span><br><span class="line">        <span class="built_in">parent</span>::<span class="title function_ invoke__">foo</span>(); <span class="comment">//</span></span><br><span class="line">        <span class="built_in">self</span>::<span class="title function_ invoke__">foo</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">who</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="keyword">__CLASS__</span>.<span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">C</span> <span class="keyword">extends</span> <span class="title">B</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">who</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="keyword">__CLASS__</span>.<span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">C::<span class="title function_ invoke__">test</span>();</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>输出<br>    A<br>    C<br>    C<br>    C</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="built_in">static</span>::<span class="title function_ invoke__">who</span>(); <span class="comment">// 留意此处,static究竟指向谁</span></span><br><span class="line">        <span class="comment">// 如果是self::who(),就都是A了.这就是特别需要注意的地方</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">who</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="built_in">static</span>::<span class="variable language_">class</span>;</span><br><span class="line">        <span class="keyword">echo</span> <span class="keyword">__CLASS__</span>.<span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span> <span class="keyword">extends</span> <span class="title">A</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        A::<span class="title function_ invoke__">foo</span>(); <span class="comment">// 非转发调用</span></span><br><span class="line">        <span class="built_in">static</span>::<span class="title function_ invoke__">foo</span>();</span><br><span class="line">        <span class="built_in">parent</span>::<span class="title function_ invoke__">foo</span>(); <span class="comment">//</span></span><br><span class="line">        <span class="built_in">self</span>::<span class="title function_ invoke__">foo</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">who</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="built_in">static</span>::<span class="variable language_">class</span>;</span><br><span class="line">        <span class="keyword">echo</span> <span class="keyword">__CLASS__</span>.<span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">C</span> <span class="keyword">extends</span> <span class="title">B</span> </span>&#123;</span><br><span class="line"><span class="comment">//    public static function who() &#123;</span></span><br><span class="line"><span class="comment">//        echo static::class;</span></span><br><span class="line"><span class="comment">//        echo __CLASS__.&quot;\n&quot;;</span></span><br><span class="line"><span class="comment">//    &#125;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">C::<span class="title function_ invoke__">test</span>();</span><br><span class="line"></span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure>
<p>输出<br>    AA<br>    CB<br>    CB<br>    CB</p>
<h2 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h2><p>通常我们喜欢封装好多类是完整和独立的,不需要从外部干预内部代码的执行.所以依赖程序员另外写代码来测试一个类中的方法是否出错,是非常不合理的.</p>
<h3 id="异常"><a href="#异常" class="headerlink" title="异常"></a>异常</h3><p>异常时从PHP5内置的Exception类(或其子类)实例化得到的特殊对象.Exception类型的对象用于存放或报告错误信息.<br>Exception类的构造方法接受两个可选的参数:消息字符串和错误代码.其提供了一些有用的方法来分析错误条件:</p>
<p><strong>Exception类的public方法</strong></p>
<table>
<thead>
<tr>
<th>方法</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td>getMessage()</td>
<td>获得传递给构造方法的消息字符串</td>
</tr>
<tr>
<td>getCode()</td>
<td>获得传递给构造方法的错误代买</td>
</tr>
<tr>
<td>getFile()</td>
<td>获得产生异常的文件</td>
</tr>
<tr>
<td>getLine()</td>
<td>获得产生异常的行号</td>
</tr>
<tr>
<td>getPrevious</td>
<td>获得一个嵌套的异常对象</td>
</tr>
<tr>
<td>getTrace()</td>
<td>获得一个多维数组,这个数组追踪导致异常的方法调用,包含方法,类,文件和参数数据</td>
</tr>
<tr>
<td>getTraceAsString()</td>
<td>获得getTrace()返回数据的字符串版本</td>
</tr>
<tr>
<td>__toString()</td>
<td>在字符串中使用Exception对象时自动调用.返回一个描述异常细节的字符串</td>
</tr>
</tbody></table>
<h3 id="异常的子类化"><a href="#异常的子类化" class="headerlink" title="异常的子类化"></a>异常的子类化</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">XmlException</span> <span class="keyword">extends</span> <span class="title">Exception</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$error</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">LibXMLError <span class="variable">$error</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable">$shortfile</span> = <span class="title function_ invoke__">basename</span>(<span class="variable">$error</span>-&gt;file);</span><br><span class="line">        <span class="variable">$msg</span> = <span class="string">&quot;[<span class="subst">&#123;$shortfile&#125;</span>, line <span class="subst">&#123;$error-&gt;line&#125;</span>, col <span class="subst">&#123;$error-&gt;column&#125;</span>]<span class="subst">&#123;$error-&gt;message&#125;</span>&quot;</span>;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;error = <span class="variable">$error</span>;</span><br><span class="line">        <span class="built_in">parent</span>::<span class="title function_ invoke__">__construct</span>(<span class="variable">$msg</span>, <span class="variable">$error</span>-&gt;code);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">getLibXmlError</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;error;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileException</span> <span class="keyword">extends</span> <span class="title">Exception</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConfException</span> <span class="keyword">extends</span> <span class="title">Exception</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Conf</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$file</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;file = <span class="variable">$file</span>;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_ invoke__">file_exists</span>(<span class="variable">$file</span>)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FileException</span>(<span class="string">&quot;file &#x27;<span class="subst">&#123;$file&#125;</span>&#x27; does not exist&#x27;&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;xml = <span class="title function_ invoke__">simplexml_load_file</span>(<span class="variable">$file</span>, <span class="literal">null</span>, LIBXML_NOERROR);</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_ invoke__">is_object</span>(<span class="variable">$this</span>-&gt;xml)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">XmlException</span>(<span class="title function_ invoke__">libxml_get_last_error</span>());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">echo</span> <span class="title function_ invoke__">gettype</span>(<span class="variable">$this</span>-&gt;xml);</span><br><span class="line">        <span class="variable">$matches</span> = <span class="variable language_">$this</span>-&gt;xml-&gt;<span class="title function_ invoke__">xpath</span>(<span class="string">&quot;/conf&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_ invoke__">count</span>(<span class="variable">$matches</span>)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ConfException</span>(<span class="string">&quot;could not find root element: conf&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">write</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_ invoke__">is_writable</span>(<span class="variable">$this</span>-&gt;file)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">FileException</span>(<span class="string">&quot;file &#x27;<span class="subst">&#123;$this-&gt;file&#125;</span>&#x27; is not writeable&#x27;&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="title function_ invoke__">file_put_contents</span>(<span class="variable">$this</span>-&gt;file, <span class="variable">$this</span>-&gt;xml-&gt;<span class="title function_ invoke__">asXML</span>());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Runner</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">init</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="variable">$conf</span> = <span class="keyword">new</span> <span class="title class_">Conf</span>(<span class="title function_ invoke__">dirname</span>(<span class="keyword">__FILE__</span>) . <span class="string">&quot;conf01.xml&quot;</span>);</span><br><span class="line">            <span class="keyword">echo</span> <span class="string">&quot;user:<span class="subst">&#123;$conf-&gt;get(&#x27;user&#x27;)&#125;</span>\n&quot;</span>;</span><br><span class="line">            <span class="keyword">echo</span> <span class="string">&quot;user:<span class="subst">&#123;$conf-&gt;get(&#x27;host&#x27;)&#125;</span>\n&quot;</span>;</span><br><span class="line">            <span class="variable">$conf</span>-&gt;<span class="title function_ invoke__">set</span>(<span class="string">&#x27;pass&#x27;</span>, <span class="string">&#x27;newpass&#x27;</span>);</span><br><span class="line">            <span class="variable">$conf</span>-&gt;<span class="title function_ invoke__">write</span>();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (FileException <span class="variable">$e</span>) &#123;</span><br><span class="line">            <span class="comment">// todo 文件权限问题或者文件不存在</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (XmlException <span class="variable">$e</span>) &#123;</span><br><span class="line">            <span class="comment">// todo XML文件损坏</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (ConfException <span class="variable">$e</span>) &#123;</span><br><span class="line">            <span class="comment">// todo 错误的XML文件格式</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (<span class="built_in">Exception</span> <span class="variable">$e</span>) &#123;</span><br><span class="line">            <span class="comment">// todo 后备捕捉器</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="内部错误类"><a href="#内部错误类" class="headerlink" title="内部错误类"></a>内部错误类</h2><p>try和catch子句主要针对的是php代码，而不是核心引擎.内部生成的错误会维护它们自己的逻辑.如果两者混为一谈，将会导致一片混乱.php7引用了error类来解决这个问题.error类和exception类实现了同一个内置接口Throwable.因此，可以使用相同的方法处理它们.</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="keyword">try</span>&#123;</span><br><span class="line">    <span class="keyword">eval</span>(<span class="string">&quot;echo &#x27;hello&#x27;&quot;</span>);</span><br><span class="line">&#125; <span class="keyword">catch</span>(<span class="built_in">Error</span> <span class="variable">$e</span>) &#123;</span><br><span class="line">    <span class="keyword">print</span> <span class="title function_ invoke__">get_class</span>(<span class="variable">$e</span>);</span><br><span class="line">    <span class="keyword">echo</span> <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">    <span class="keyword">print</span> <span class="variable">$e</span>-&gt;<span class="title function_ invoke__">getMessage</span>();</span><br><span class="line">&#125; <span class="keyword">catch</span> (<span class="built_in">Exception</span> <span class="variable">$e</span>) &#123;</span><br><span class="line">    <span class="comment">// todo</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>输出:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ParseError</span><br><span class="line">syntax error, unexpected end of file, expecting &#x27;,&#x27; or &#x27;;&#x27;</span><br></pre></td></tr></table></figure>

<p>如上所示，可以在catch子句中通过制定Error这个父类和其子类来捕捉相匹配的内部错误.内部错误有下:</p>
<table>
<thead>
<tr>
<th>错误</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>ArithmeticError</td>
<td>当发生与数学计算（特别是位运算）相关的错误时被抛出</td>
</tr>
<tr>
<td>AssertionError</td>
<td>当assert()语言结构（调试中）断言失败时被抛出</td>
</tr>
<tr>
<td>DivisionByZeroError</td>
<td>进行除零计算时被抛出</td>
</tr>
<tr>
<td>ParseError</td>
<td>在运行时解析php出错时抛出</td>
</tr>
<tr>
<td>TypeError</td>
<td>当错误类型的参数被传递给方法，方法返回一个错误类型的参数，或是传递给方法的参数是的数量不正确时被抛出</td>
</tr>
</tbody></table>
<h2 id="Final类和方法"><a href="#Final类和方法" class="headerlink" title="Final类和方法"></a>Final类和方法</h2><p>final关键字可以终止类的继承.final类不能有子类,final方法不能被覆写.</p>
<h2 id="使用拦截器"><a href="#使用拦截器" class="headerlink" title="使用拦截器"></a>使用拦截器</h2><p><strong>拦截器方法</strong></p>
<table>
<thead>
<tr>
<th>方法</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td>__get($property)</td>
<td>访问未定义的属性时被调用</td>
</tr>
<tr>
<td>__set($property, $value)</td>
<td>给未定义的属性赋值时被调用</td>
</tr>
<tr>
<td>__isset($property)</td>
<td>对未定义的属性调用isset()时被调用</td>
</tr>
<tr>
<td>__unset($property)</td>
<td>对未定义的属性调用unset()时被调用</td>
</tr>
<tr>
<td>__call($property, $arg_array)</td>
<td>调用未定义非静态的方法时被调用</td>
</tr>
<tr>
<td>__callStatic($property, $arg_array)</td>
<td>调用未定义的静态方法时被调用</td>
</tr>
</tbody></table>
<h2 id="析构方法"><a href="#析构方法" class="headerlink" title="析构方法"></a>析构方法</h2><p>在对象被垃圾收集器收集之前(即对象从内存中删除之前)自动调用.可以使用这个方法进行最后必要的清理工作.</p>
<h2 id="使用-clone-复制对象"><a href="#使用-clone-复制对象" class="headerlink" title="使用__clone()复制对象"></a>使用__clone()复制对象</h2><p>在对象调用clone时,可以通过__clone()实现控制复制什么.</p>
<p>在复制对象属性时只会复制引用,并不会复制引用的对象.<br>如果不希望对象属性(对象的属性是其他对象)在复制之后被共享,则可以显示地在__clone()方法中复制指向的对象.</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">__clone</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="variable language_">$this</span>-&gt;id = <span class="number">0</span>; <span class="comment">// 控制复制属性</span></span><br><span class="line">    <span class="variable language_">$this</span>-&gt;account = <span class="keyword">clone</span> <span class="variable language_">$this</span>-&gt;account; <span class="comment">// 复制对象属性(不这样做会引用该对象属性)</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="定义对象的字符串值"><a href="#定义对象的字符串值" class="headerlink" title="定义对象的字符串值"></a>定义对象的字符串值</h2><p>__toString()方法</p>
<h2 id="回调-匿名函数和闭包"><a href="#回调-匿名函数和闭包" class="headerlink" title="回调 匿名函数和闭包"></a>回调 匿名函数和闭包</h2><p>虽然匿名函数不是严格意义上的面向对象的特性,但是它非常有用.</p>
<p>利用回调,可以在运行时将与组件的核心任务没有直接关系的功能插入到组件中.有了组件回调,就可以在不知道上下文的情况下扩展他人的代码.</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Product</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$name</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="variable">$price</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$name</span>, <span class="variable">$price</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;name = <span class="variable">$name</span>;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;price = <span class="variable">$price</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ProcessSale</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$call_backs</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">registerCallBack</span>(<span class="params"><span class="variable">$call_back</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_ invoke__">is_callable</span>(<span class="variable">$call_back</span>)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">&quot;callback not callable&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;call_backs[] = <span class="variable">$call_back</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 回调方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> $product</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">sale</span>(<span class="params"><span class="variable">$product</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="string">&quot;<span class="subst">&#123;$product-&gt;name&#125;</span>:processing\n&quot;</span>;</span><br><span class="line">        <span class="keyword">foreach</span> (<span class="variable language_">$this</span>-&gt;call_backs <span class="keyword">as</span> <span class="variable">$call_back</span>) &#123;</span><br><span class="line">            <span class="title function_ invoke__">call_user_func</span>(<span class="variable">$call_back</span>, <span class="variable">$product</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Mailer</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">sendMail</span>(<span class="params"><span class="variable">$product</span></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="string">&quot;Send Mail <span class="subst">&#123;$product-&gt;name&#125;</span>&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">$logger</span> = <span class="function"><span class="keyword">function</span> (<span class="params"><span class="variable">$product</span></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">echo</span> <span class="string">&quot;logging <span class="subst">&#123;$product-&gt;name&#125;</span>\n&quot;</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 闭包</span></span><br><span class="line"><span class="comment"> * Class Totalizer</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Totalizer</span></span>&#123;</span><br><span class="line">    <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">warnAmount</span>(<span class="params"><span class="variable">$amt</span></span>) </span>&#123;</span><br><span class="line">        <span class="variable">$count</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"><span class="variable">$product</span></span>) <span class="keyword">use</span> (<span class="params"><span class="variable">$amt</span>, &amp;<span class="variable">$count</span></span>) </span>&#123;</span><br><span class="line">            <span class="variable">$count</span> += <span class="variable">$product</span>-&gt;price;</span><br><span class="line">            <span class="keyword">echo</span> <span class="string">&quot;\n<span class="subst">&#123;$product-&gt;name&#125;</span> is <span class="subst">&#123;$product-&gt;price&#125;</span>\n&quot;</span>;</span><br><span class="line">            <span class="keyword">if</span> (<span class="variable">$count</span> &gt; <span class="variable">$amt</span>) &#123;</span><br><span class="line">                <span class="keyword">echo</span> <span class="string">&quot;High price reached <span class="subst">&#123;$count&#125;</span>\n&quot;</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">$process</span> = <span class="keyword">new</span> <span class="title class_">ProcessSale</span>();</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="variable">$process</span>-&gt;<span class="title function_ invoke__">registerCallBack</span>(<span class="variable">$logger</span>); <span class="comment">// 回调 匿名函数</span></span><br><span class="line">    <span class="variable">$process</span>-&gt;<span class="title function_ invoke__">registerCallBack</span>([<span class="keyword">new</span> <span class="title class_">Mailer</span>(), <span class="string">&#x27;sendMail&#x27;</span>]); <span class="comment">// 回调 对象方法 #1</span></span><br><span class="line">    <span class="variable">$process</span>-&gt;<span class="title function_ invoke__">registerCallBack</span>(<span class="title class_">Totalizer</span>::<span class="title function_ invoke__">warnAmount</span>(<span class="number">3</span>)); <span class="comment">// 回调 静态方法 闭包</span></span><br><span class="line">&#125; <span class="keyword">catch</span> (<span class="built_in">Exception</span> <span class="variable">$e</span>) &#123;</span><br><span class="line">    <span class="keyword">die</span>(<span class="variable">$e</span>-&gt;<span class="title function_ invoke__">getMessage</span>());</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$process</span>-&gt;<span class="title function_ invoke__">sale</span>(<span class="keyword">new</span> <span class="title class_">Product</span>(<span class="string">&#x27;shoes&#x27;</span>, <span class="number">6</span>));</span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;\n&quot;</span>;</span><br><span class="line"><span class="variable">$process</span>-&gt;<span class="title function_ invoke__">sale</span>(<span class="keyword">new</span> <span class="title class_">Product</span>(<span class="string">&#x27;pen&#x27;</span>, <span class="number">12</span>));</span><br></pre></td></tr></table></figure>

<p>注意在上述代码中的#1处的用法</p>
<p>这里传递了一个数组,其第一个元素是对象,第二个元素是对象中的方法名(字符串形式).is_callable可以智能检测这类数组.另外,这种写法在array_walk等中也常见</p>
<h2 id="匿名类"><a href="#匿名类" class="headerlink" title="匿名类"></a>匿名类</h2><p>当需要从很小的类中创建和继承实例，特别是这个类很简单且特定于局部上下文时，匿名类很有用。 </p>
<h1 id="对象工具"><a href="#对象工具" class="headerlink" title="对象工具"></a>对象工具</h1><p>本章主要内容:</p>
<ul>
<li>包:将代码按逻辑分类打包</li>
<li>命名空间:将代码封装在独立的单元中</li>
<li>包含路径:为类库代码设置访问路径</li>
<li>类函数和对象函数:测试对象,类,属性和方法的函数</li>
<li>反射API:一组强大的内置类,可以在代码运行时访问类信息</li>
</ul>
<h2 id="PHP和包"><a href="#PHP和包" class="headerlink" title="PHP和包"></a>PHP和包</h2><h2 id="PHP包和命名空间"><a href="#PHP包和命名空间" class="headerlink" title="PHP包和命名空间"></a>PHP包和命名空间</h2><p>尽管php本身不支持包的概念,开发人员却一直在使用<em>文件系统</em>和<em>命名模式</em>将代码组织成类似于包的结构.</p>
<h3 id="命名空间"><a href="#命名空间" class="headerlink" title="命名空间"></a>命名空间</h3><p>命名空间是一个容器,他可以将类 函数和变量放在其中.在命名空间中,可以无条件访问这些项.在命名空间之外,必须导入或引用命名空间,才能访问它所包含的项.</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">才发现这个命名空间和那个函数作用域很像,居然可以这个样子来思考这个命名空间.</span><br></pre></td></tr></table></figure>

<h3 id="使用文件系统模拟包"><a href="#使用文件系统模拟包" class="headerlink" title="使用文件系统模拟包"></a>使用文件系统模拟包</h3><p>无论哪个版本的php中,都可以使用提供了包结构的文件系统来组织类.</p>
<h3 id="PEAR风格的命名方式"><a href="#PEAR风格的命名方式" class="headerlink" title="PEAR风格的命名方式"></a>PEAR风格的命名方式</h3><p>如果不使用命名空间,可以使用文件系统来定义包.每个类都根据包路径来命名,每个路径名以下划线分割.</p>
<h3 id="包含路径"><a href="#包含路径" class="headerlink" title="包含路径"></a>包含路径</h3><p>要使程序代码不再直接依赖于类库代码程序中包含的类库,需要将调用类库的代码和类库代码进行解耦,即让文件可以在系统的任何地方进行调用.这可以通过把包放到include_path指定引用目录中即可.</p>
<h2 id="自动加载"><a href="#自动加载" class="headerlink" title="自动加载"></a>自动加载</h2><p>__autoload()方法是一种根据类和文件的结构,管理类库文件包含的有效方法.</p>
<p>一个文件定义一个类,一一对应,便于管理.这种方法虽然会带来额外的开销(包含文件会带来开销),但这种组织方式特别有效.尤其是系统需要在运行时使用新类的时候.</p>
<h2 id="类函数和对象函数"><a href="#类函数和对象函数" class="headerlink" title="类函数和对象函数"></a>类函数和对象函数</h2><p>在PHP代码运行时可能无法知道正在使用的类是哪个,这是因为php中类是可以通过字符串动态加载到,而字符串是不固定的.</p>
<p>在实际开发中,需要先检查类是否存在,它是否拥有使用的方法等,以避免可能存在的风险.</p>
<h3 id="查找类"><a href="#查找类" class="headerlink" title="查找类"></a>查找类</h3><p>class_exists()函数接受表示类的字符串,检查并返回布尔值.</p>
<p>print_r(get_declared_classess())可以列出用户定义的类和php内置的类.注意它只返回在函数调用时已声明的类.可以继续运行require等增加脚本中类的数目.</p>
<h3 id="了解对象或类"><a href="#了解对象或类" class="headerlink" title="了解对象或类"></a>了解对象或类</h3><p><a target="_blank" rel="noopener" href="http://php.net/manual/zh/function.get-class.php">get_class</a></p>
<p>返回对象实例 object 所属类的名字.</p>
<p><a target="_blank" rel="noopener" href="http://php.net/manual/zh/language.operators.type.php">instanceof</a> </p>
<p>用于确定一个 PHP 变量是否属于某一类 class 的实例</p>
<h3 id="了解类中的方法"><a href="#了解类中的方法" class="headerlink" title="了解类中的方法"></a>了解类中的方法</h3><p>get_class_method () 获取一个类中所有的public方法</p>
<p>is_callable() 验证变量是否可以作为函数被调用</p>
<p>method_exists() 判断类中是否存在指定方法</p>
<h3 id="了解类的属性"><a href="#了解类的属性" class="headerlink" title="了解类的属性"></a>了解类的属性</h3><p>get_class_vars() 返回类中public属性</p>
<h3 id="了解继承"><a href="#了解继承" class="headerlink" title="了解继承"></a>了解继承</h3><p>get_parent_class()</p>
<p>is_subclass_of()<br>只会告诉继承关系,而不会告诉类是否实现了一个接口.</p>
<p>instanceof </p>
<p>class_implements()<br>返回由接口构成的数组.</p>
<h4 id="展示代码"><a href="#展示代码" class="headerlink" title="展示代码"></a>展示代码</h4><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">who</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">test_private</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span> <span class="keyword">extends</span> <span class="title">A</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">who</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">C</span> <span class="keyword">extends</span> <span class="title">B</span> </span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title function_ invoke__">print_r</span>(<span class="title function_ invoke__">get_class_methods</span>(<span class="keyword">new</span> <span class="title function_ invoke__">C</span>()));</span><br><span class="line"></span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">is_callable</span>([<span class="keyword">new</span> <span class="title function_ invoke__">C</span>(), <span class="string">&#x27;foo&#x27;</span>])); <span class="comment">// true</span></span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">is_callable</span>([<span class="keyword">new</span> <span class="title function_ invoke__">C</span>(), <span class="string">&#x27;test_private&#x27;</span>])); <span class="comment">// false</span></span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">method_exists</span>(<span class="string">&#x27;C&#x27;</span>, <span class="string">&#x27;foo&#x27;</span>)); <span class="comment">// true</span></span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">method_exists</span>(<span class="string">&#x27;C&#x27;</span>, <span class="string">&#x27;test_private&#x27;</span>)); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">get_parent_class</span>(<span class="keyword">new</span> <span class="title function_ invoke__">C</span>())); <span class="comment">// B</span></span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="title function_ invoke__">is_subclass_of</span>(<span class="keyword">new</span> <span class="title function_ invoke__">C</span>(),<span class="string">&quot;A&quot;</span>)); <span class="comment">// true</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="方法调用"><a href="#方法调用" class="headerlink" title="方法调用"></a>方法调用</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$product</span> = <span class="title function_ invoke__">getProduct</span>(); <span class="comment">// 获得对象</span></span><br><span class="line"><span class="variable">$method</span> = <span class="string">&#x27;getTitle&#x27;</span>; <span class="comment">// 定义方法名</span></span><br><span class="line"><span class="keyword">print</span> <span class="variable">$product</span>-&gt;<span class="variable">$method</span>(); <span class="comment">// 调用方法</span></span><br></pre></td></tr></table></figure>

<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$returnVal</span> = <span class="title function_ invoke__">call_user_func</span>(<span class="string">&#x27;myFunction&#x27;</span>);</span><br><span class="line"><span class="variable">$returnVal</span> = <span class="title function_ invoke__">call_user_func</span>([<span class="variable">$myObject</span>, <span class="string">&#x27;methodName&#x27;</span>]); <span class="comment">// 调用类方法 call_user_function_array()</span></span><br></pre></td></tr></table></figure>

<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$product</span> = <span class="title function_ invoke__">getProduct</span>(); <span class="comment">// 获得对象</span></span><br><span class="line"></span><br><span class="line"><span class="title function_ invoke__">call_user_func</span>([<span class="variable">$product</span>, <span class="string">&#x27;setDiscount&#x27;</span>], <span class="number">20</span>);</span><br><span class="line">等价于</span><br><span class="line"><span class="variable">$product</span>-&gt;<span class="title function_ invoke__">setDiscount</span>(<span class="number">20</span>);</span><br><span class="line">等价于</span><br><span class="line"><span class="variable">$method</span> = <span class="string">&#x27;setDiscount&#x27;</span>;</span><br><span class="line"><span class="variable">$product</span>-&gt;<span class="variable">$method</span>(<span class="number">20</span>);;</span><br></pre></td></tr></table></figure>

<h2 id="反射API"><a href="#反射API" class="headerlink" title="反射API"></a>反射API</h2><p>PHP中的反射API就像java中的java.lang.reflect包一样.它由一系列可以分析属性&#x2F;方法和类的内置类构成.这个比上述的类函数要有方便灵活有效地多.</p>
<h3 id="入门"><a href="#入门" class="headerlink" title="入门"></a>入门</h3><p>反射API的部分类</p>
<table>
<thead>
<tr>
<th>类</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td>Reflection</td>
<td>为类的摘要信息提供静态函数export()</td>
</tr>
<tr>
<td>ReflectionClass</td>
<td>类信息和工具</td>
</tr>
<tr>
<td>ReflectionMethod</td>
<td>类方法信息和工具</td>
</tr>
<tr>
<td>ReflectionParameter</td>
<td>方法参数信息</td>
</tr>
<tr>
<td>ReflectionProperty</td>
<td>类属性信息</td>
</tr>
<tr>
<td>ReflectionFunction</td>
<td>函数信息和工具</td>
</tr>
<tr>
<td>ReflectionExtension</td>
<td>PHP扩展信息</td>
</tr>
<tr>
<td>ReflectionException</td>
<td>错误类</td>
</tr>
<tr>
<td>ReflectionZendExtension</td>
<td>PHP Zend扩展信息</td>
</tr>
</tbody></table>
<p>利用反射API中的这些类,可以在运行时访问对象&#x2F;函数和脚本中的扩展的信息</p>
<p><em>个人理解</em></p>
<p><em>这本书有一个缺点,好多东西都是点到为止,对我这样的初学者来说还是有不少麻烦的.</em><br><em>这一章主要讲的就是代码结构化的概念,都是围绕着如何结构化的组织代码.</em><br><em>这本书出的有些早,都七八年了.所以有些都成了历史了.尤其是现在的开发大都基于框架的时候.有些东西成了共识,无需赘言.</em></p>
<p><em>其实也是分别对应了我写代码的一些历程.</em><br><em>一开始的时候我都是把所有的代码写在一个文件里.</em><br><em>慢慢的发现有些代码是重复的,所以就把那些重复的代码封装成函数,按需调用.</em><br><em>接着就是把常用的函数单独放到一个个文件中,需要的时候require.</em><br><em>然后接触到到类的概念,就把一些常用的东西封装成类.这个时候的类在我看来就是一堆函数的组合.也就是说,和函数相比其实也没有什么区别.对我而言,如今我能真正获取到的优势就是可以把功能相关的方法组合起来,方便记忆与调用.</em><br><em>接着接触到框架,知道了如何使用路径和名称把类放置到一个个合适的地方,以方便使用php自带的方法引用那些.在这里知道了namespace的概念.</em><br><em>其实我现在就是处在这个尴尬的位置.</em><br><em>因为我定义的所有类,就是一堆方法的零碎组合.这就是我需要学习的地方,即设计模式.其实就是从类的角度思考代码.</em>****</p>
<p><em>这一章于我而言,其实就是学到了反射这个概念.这是以后内容的基础.</em><br><em>所谓反射,在我看来,就是get_class_name之类的获取类信息的函数的升级版.</em><br><em>好吧,刚刚我也说出了我对对象和函数的认识.</em><br><em>不过说起来,一年多的代码编写中,我其实一直用的都是过程式的编程思维.所以这本书的内容对我而言是一个挑战,更是一个突破.</em><br><em>见识到了按接口编程,虽然现在不熟悉,但我肯定是能掌握的.</em><br><em>因为我这一步步走来,曾经不知道有多少坎如今看来已是寻常~~~</em></p>
<h1 id="对象与设计"><a href="#对象与设计" class="headerlink" title="对象与设计"></a>对象与设计</h1><p>本章内容:</p>
<ul>
<li>设计基础:设计是什么?面向对象设计和过程式编程有什么不同?</li>
<li>类的内容:如果决定一个类应该包含什么</li>
<li>封装:在类接口后面隐藏实现和数据</li>
<li>多态:使用一个共同的父类,允许在运行是透明地替换特定的子类</li>
<li>UML</li>
</ul>
<h1 id="什么是设计模式-为什么使用它们"><a href="#什么是设计模式-为什么使用它们" class="headerlink" title="什么是设计模式?为什么使用它们"></a>什么是设计模式?为什么使用它们</h1><p>本章内容:</p>
<ul>
<li>模式基础:什么是设计模式</li>
<li>模式结构:每个设计模式的关键元素</li>
<li>模式收益:为何模式值得花时间学习</li>
</ul>
<h1 id="模式原则"><a href="#模式原则" class="headerlink" title="模式原则"></a>模式原则</h1><p>本章内容:</p>
<ul>
<li>组合:如果通过聚合对象来获得比只是用继承更好的灵活性</li>
<li>解耦:如何降低系统中元素的依赖性</li>
<li>接口的作用:模式和多态</li>
<li>模式分类:模式类别</li>
</ul>
<h2 id="组合与继承"><a href="#组合与继承" class="headerlink" title="组合与继承"></a>组合与继承</h2><p>继承是一种强大的设计方式，它可以有效应对环境及上下文的改变。但是它也会限制灵活性，特别是类承担太多的职责的时候。</p>
<p>组合优于继承。</p>
<h1 id="生成对象"><a href="#生成对象" class="headerlink" title="生成对象"></a>生成对象</h1><p>本章内容</p>
<ul>
<li>单例（Singleton）模式：只生成一个对象实例的特殊类</li>
<li>工厂方法（Factory Method)模式：构建创造者类的继承层次</li>
<li>抽象工厂（Abstract Factory)模式：对功能相关的产品进行分组</li>
<li>原形（Prototype）模式：通过克隆生成对象</li>
<li>服务定位器（Service Locator）模式：向系统索要对象</li>
<li>依赖注入（Dependency Injection）模式：让系统给我们对象</li>
</ul>
<h2 id="生成对象的问题及解决方案"><a href="#生成对象的问题及解决方案" class="headerlink" title="生成对象的问题及解决方案"></a>生成对象的问题及解决方案</h2><h2 id="单例模式"><a href="#单例模式" class="headerlink" title="单例模式"></a>单例模式</h2><p>虽然全局变量是面向对象程序员都讨厌的东西，但是为了所有的类能够方便地访问变量，我们不惜代价忍受全局访问的缺陷。<br>命名空间可以在一定程度上避免命名的冲突，我们至少可以将变量作用域限制在包内，这意味着第三方库与我们自己库中的变量命名发生冲突的可能性大大降低了。即便如此，在命名空间内部依然有命名冲突的风险。</p>
<p>单例模式和全局变量相比如何？两者都容易被误用。因为系统中的任何地方都可以访问单例，所以也容易引发难以调试的依赖关系。在面向对象的设计中，单例优于全局变量，因为单例可以防止其他代码向单例写入错误的数据类型。</p>
<h2 id="工厂方法模式"><a href="#工厂方法模式" class="headerlink" title="工厂方法模式"></a>工厂方法模式</h2><p>面向对象的设计强调抽象类高于实现类，也就是说，我们应该尽量一般化，而不是特殊化。工厂方法模式能够解决代码关注抽象类型是如何创建对象实例的问题。答案就是用实现类负责实例化对象。</p>

    </div>

    
    
    

      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/PHP/" rel="tag"># PHP</a>
              <a href="/tags/%E5%9B%BE%E4%B9%A6/" rel="tag"># 图书</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/posts/47365.html" rel="prev" title="服务器开启3306端口">
      <i class="fa fa-chevron-left"></i> 服务器开启3306端口
    </a></div>
      <div class="post-nav-item">
    <a href="/posts/36837.html" rel="next" title="phpstorm wamp3 配置xdebug">
      phpstorm wamp3 配置xdebug <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          
    <div class="comments" id="valine-comments"></div>

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%AF%B9%E8%B1%A1%E5%9F%BA%E7%A1%80"><span class="nav-number">1.</span> <span class="nav-text">对象基础</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%92%8C%E5%AF%B9%E8%B1%A1"><span class="nav-number">1.1.</span> <span class="nav-text">类和对象</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BC%96%E5%86%99%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%B1%BB"><span class="nav-number">1.1.1.</span> <span class="nav-text">编写第一个类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1-%E6%88%96%E4%B8%A4%E4%B8%AA"><span class="nav-number">1.1.2.</span> <span class="nav-text">第一个对象(或两个)</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%AE%BE%E7%BD%AE%E7%B1%BB%E4%B8%AD%E7%9A%84%E5%B1%9E%E6%80%A7"><span class="nav-number">1.2.</span> <span class="nav-text">设置类中的属性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95"><span class="nav-number">1.3.</span> <span class="nav-text">使用方法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%82%E6%95%B0%E5%92%8C%E7%B1%BB%E5%9E%8B"><span class="nav-number">1.4.</span> <span class="nav-text">参数和类型</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B"><span class="nav-number">1.4.1.</span> <span class="nav-text">基本类型</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="nav-number">1.4.1.1.</span> <span class="nav-text">基本数据类型</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E8%8E%B7%E5%BE%97%E6%8F%90%E7%A4%BA-%E5%AF%B9%E8%B1%A1%E7%B1%BB%E5%9E%8B"><span class="nav-number">1.4.1.2.</span> <span class="nav-text">获得提示:对象类型</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF"><span class="nav-number">1.5.</span> <span class="nav-text">继承</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF%E9%97%AE%E9%A2%98"><span class="nav-number">1.5.1.</span> <span class="nav-text">继承问题</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E7%BB%A7%E6%89%BF"><span class="nav-number">1.5.2.</span> <span class="nav-text">使用继承</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%E5%92%8C%E7%BB%A7%E6%89%BF"><span class="nav-number">1.5.2.1.</span> <span class="nav-text">构造方法和继承</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E8%B0%83%E7%94%A8%E8%A2%AB%E8%A6%86%E5%86%99%E7%9A%84%E6%96%B9%E6%B3%95"><span class="nav-number">1.5.2.2.</span> <span class="nav-text">调用被覆写的方法</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#public-private-protected-%E7%AE%A1%E7%90%86%E7%B1%BB%E7%9A%84%E8%AE%BF%E9%97%AE"><span class="nav-number">1.5.3.</span> <span class="nav-text">public private protected:管理类的访问</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E9%AB%98%E7%BA%A7%E7%89%B9%E6%80%A7"><span class="nav-number">2.</span> <span class="nav-text">高级特性</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E5%92%8C%E5%B1%9E%E6%80%A7"><span class="nav-number">2.1.</span> <span class="nav-text">静态方法和属性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B8%B8%E9%87%8F%E5%B1%9E%E6%80%A7"><span class="nav-number">2.2.</span> <span class="nav-text">常量属性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8A%BD%E8%B1%A1%E7%B1%BB"><span class="nav-number">2.3.</span> <span class="nav-text">抽象类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8E%A5%E5%8F%A3"><span class="nav-number">2.4.</span> <span class="nav-text">接口</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#trait"><span class="nav-number">2.5.</span> <span class="nav-text">trait</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%BB%B6%E8%BF%9F%E9%9D%99%E6%80%81%E7%BB%91%E5%AE%9A-static%E5%85%B3%E9%94%AE%E5%AD%97"><span class="nav-number">2.6.</span> <span class="nav-text">延迟静态绑定:static关键字</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86"><span class="nav-number">2.7.</span> <span class="nav-text">错误处理</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%BC%82%E5%B8%B8"><span class="nav-number">2.7.1.</span> <span class="nav-text">异常</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%BC%82%E5%B8%B8%E7%9A%84%E5%AD%90%E7%B1%BB%E5%8C%96"><span class="nav-number">2.7.2.</span> <span class="nav-text">异常的子类化</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%86%85%E9%83%A8%E9%94%99%E8%AF%AF%E7%B1%BB"><span class="nav-number">2.8.</span> <span class="nav-text">内部错误类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Final%E7%B1%BB%E5%92%8C%E6%96%B9%E6%B3%95"><span class="nav-number">2.9.</span> <span class="nav-text">Final类和方法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E6%8B%A6%E6%88%AA%E5%99%A8"><span class="nav-number">2.10.</span> <span class="nav-text">使用拦截器</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%9E%90%E6%9E%84%E6%96%B9%E6%B3%95"><span class="nav-number">2.11.</span> <span class="nav-text">析构方法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8-clone-%E5%A4%8D%E5%88%B6%E5%AF%B9%E8%B1%A1"><span class="nav-number">2.12.</span> <span class="nav-text">使用__clone()复制对象</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AE%9A%E4%B9%89%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%80%BC"><span class="nav-number">2.13.</span> <span class="nav-text">定义对象的字符串值</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%9B%9E%E8%B0%83-%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0%E5%92%8C%E9%97%AD%E5%8C%85"><span class="nav-number">2.14.</span> <span class="nav-text">回调 匿名函数和闭包</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8C%BF%E5%90%8D%E7%B1%BB"><span class="nav-number">2.15.</span> <span class="nav-text">匿名类</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%AF%B9%E8%B1%A1%E5%B7%A5%E5%85%B7"><span class="nav-number">3.</span> <span class="nav-text">对象工具</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#PHP%E5%92%8C%E5%8C%85"><span class="nav-number">3.1.</span> <span class="nav-text">PHP和包</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#PHP%E5%8C%85%E5%92%8C%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4"><span class="nav-number">3.2.</span> <span class="nav-text">PHP包和命名空间</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4"><span class="nav-number">3.2.1.</span> <span class="nav-text">命名空间</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E6%A8%A1%E6%8B%9F%E5%8C%85"><span class="nav-number">3.2.2.</span> <span class="nav-text">使用文件系统模拟包</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#PEAR%E9%A3%8E%E6%A0%BC%E7%9A%84%E5%91%BD%E5%90%8D%E6%96%B9%E5%BC%8F"><span class="nav-number">3.2.3.</span> <span class="nav-text">PEAR风格的命名方式</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8C%85%E5%90%AB%E8%B7%AF%E5%BE%84"><span class="nav-number">3.2.4.</span> <span class="nav-text">包含路径</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD"><span class="nav-number">3.3.</span> <span class="nav-text">自动加载</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%87%BD%E6%95%B0%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%87%BD%E6%95%B0"><span class="nav-number">3.4.</span> <span class="nav-text">类函数和对象函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%9F%A5%E6%89%BE%E7%B1%BB"><span class="nav-number">3.4.1.</span> <span class="nav-text">查找类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BA%86%E8%A7%A3%E5%AF%B9%E8%B1%A1%E6%88%96%E7%B1%BB"><span class="nav-number">3.4.2.</span> <span class="nav-text">了解对象或类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BA%86%E8%A7%A3%E7%B1%BB%E4%B8%AD%E7%9A%84%E6%96%B9%E6%B3%95"><span class="nav-number">3.4.3.</span> <span class="nav-text">了解类中的方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BA%86%E8%A7%A3%E7%B1%BB%E7%9A%84%E5%B1%9E%E6%80%A7"><span class="nav-number">3.4.4.</span> <span class="nav-text">了解类的属性</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BA%86%E8%A7%A3%E7%BB%A7%E6%89%BF"><span class="nav-number">3.4.5.</span> <span class="nav-text">了解继承</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E5%B1%95%E7%A4%BA%E4%BB%A3%E7%A0%81"><span class="nav-number">3.4.5.1.</span> <span class="nav-text">展示代码</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8"><span class="nav-number">3.4.6.</span> <span class="nav-text">方法调用</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%8D%E5%B0%84API"><span class="nav-number">3.5.</span> <span class="nav-text">反射API</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%85%A5%E9%97%A8"><span class="nav-number">3.5.1.</span> <span class="nav-text">入门</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%AF%B9%E8%B1%A1%E4%B8%8E%E8%AE%BE%E8%AE%A1"><span class="nav-number">4.</span> <span class="nav-text">对象与设计</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%BF%E7%94%A8%E5%AE%83%E4%BB%AC"><span class="nav-number">5.</span> <span class="nav-text">什么是设计模式?为什么使用它们</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%A8%A1%E5%BC%8F%E5%8E%9F%E5%88%99"><span class="nav-number">6.</span> <span class="nav-text">模式原则</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%84%E5%90%88%E4%B8%8E%E7%BB%A7%E6%89%BF"><span class="nav-number">6.1.</span> <span class="nav-text">组合与继承</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E7%94%9F%E6%88%90%E5%AF%B9%E8%B1%A1"><span class="nav-number">7.</span> <span class="nav-text">生成对象</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%94%9F%E6%88%90%E5%AF%B9%E8%B1%A1%E7%9A%84%E9%97%AE%E9%A2%98%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88"><span class="nav-number">7.1.</span> <span class="nav-text">生成对象的问题及解决方案</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F"><span class="nav-number">7.2.</span> <span class="nav-text">单例模式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F"><span class="nav-number">7.3.</span> <span class="nav-text">工厂方法模式</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">陈孟辉</p>
  <div class="site-description" itemprop="description">日积月藏，不做咸鱼。这里是陈孟辉的个人学习笔记，现就职于北京瑞友科技，负责维护企业ERP系统。</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">170</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">45</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">60</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      Links
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="http://tool.oschina.net/uploads/apidocs/jquery/regexp.html" title="http:&#x2F;&#x2F;tool.oschina.net&#x2F;uploads&#x2F;apidocs&#x2F;jquery&#x2F;regexp.html" rel="noopener" target="_blank">正则表达式</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://www.cs.usfca.edu/~galles/visualization/Algorithms.html" title="https:&#x2F;&#x2F;www.cs.usfca.edu&#x2F;~galles&#x2F;visualization&#x2F;Algorithms.html" rel="noopener" target="_blank">算法图示</a>
        </li>
    </ul>
  </div>

      </div>
        <div class="back-to-top motion-element">
          <i class="fa fa-arrow-up"></i>
          <span>0%</span>
        </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2024</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">陈孟辉</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
    <span title="站点总字数">204k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">3:06</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>

<script src="/js/utils.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  




  
<script src="/js/local-search.js"></script>













  

  


<script>
NexT.utils.loadComments(document.querySelector('#valine-comments'), () => {
  NexT.utils.getScript('//unpkg.com/valine/dist/Valine.min.js', () => {
    var GUEST = ['nick', 'mail', 'link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item => {
      return GUEST.includes(item);
    });
    new Valine({
      el         : '#valine-comments',
      verify     : true,
      notify     : true,
      appId      : '9jQqXQuURk2dvsv5oVh9D0VM-gzGzoHsz',
      appKey     : 'YfjrSNHQAtj63yeNmdmrLlLw',
      placeholder: "Just go go",
      avatar     : 'mm',
      meta       : guest,
      pageSize   : '10' || 10,
      visitor    : false,
      lang       : '' || 'zh-cn',
      path       : location.pathname,
      recordIP   : true,
      serverURLs : ''
    });
  }, window.Valine);
});
</script>

</body>
</html>
